using System;
using System.IO;
using Agile.Common;

namespace Agile.Genie.Descriptors
{
    /// <summary>
    /// Instantiates the right VisualStudioProjectFile sub class
    /// for the given file.
    /// Simple Factory 'pattern'
    /// </summary>
    public sealed class VisualStudioProjectFileFactory
    {
        /// <summary>
        /// Do not Construct.
        /// </summary>
        private VisualStudioProjectFileFactory()
        {
        }

        /// <summary>
        /// Instantiates the appropriate VisualStudioProjectFile.
        /// </summary>
        /// <param name="file"></param>
        /// <returns>e.g. A VS2003 or VS2005 project file class.</returns>
        public static VisualStudioProjectFile InstantiateFrom(FileInfo file)
        {
            string version = VisualStudioProjectFile.GetVersion(file);

            if (version == "2003")
                return VisualStudioProjectFile2003.Build(file);
            else if (version == "2005")
                return VisualStudioProjectFile2005.Build(file);
            throw new AgileCommonException("Unknown visual studio version for the given project file: " + file.FullName);
        }

        /// <summary>
        /// Instantiates the appropriate VisualStudioProjectFile.
        /// </summary>
        /// <param name="projectFile"></param>
        /// <returns>e.g. A VS2003 or VS2005 project file class.</returns>
        public static VisualStudioProjectFile Build(FileInfo projectFile)
        {
            if (projectFile == null)
                throw new ArgumentNullException("projectFile", "project file is required.");

            if (!projectFile.Extension.Equals(".csproj")
                && !projectFile.Extension.Equals(".vbproj"))
                throw new AgileCommonException(string.Format("Invalid project file type: {0}", projectFile.Extension));

            string version = VisualStudioProjectFile.GetVersion(projectFile);

            if (version == "2003")
                return VisualStudioProjectFile2003.Build(projectFile);
         
            // the 2005 version does the trick for 2008 too
            return VisualStudioProjectFile2005.Build(projectFile);
        }

        /// <summary>
        /// Instantiate a new assembly reference with the assembly name
        /// and the base directory to search through.
        /// </summary>
        /// <remarks>Use this when the project has a reference a dll.
        /// Must be a reference that there is a project file for as an exception gets
        /// thrown if the project file is not found.</remarks>
        /// <returns></returns>
        public static VisualStudioProjectFile InstantiateFromDllReference(string assemblyName
                                                                          , DirectoryInfo rootDirectory)
        {
            // Load the project files that are in the given directory.
            VisualStudioProjectFileCache.GetInstance().LoadedProjectFiles.LoadProjectFilesIn(rootDirectory);

            VisualStudioProjectFile project =
                VisualStudioProjectFileCache.GetInstance().LoadedProjectFiles.GetByAssemblyName(assemblyName);

            if (project != null)
                return project;
            // Try to find the project file using a soft search of the assembly name
            project =
                VisualStudioProjectFileCache.GetInstance().LoadedProjectFiles.GetByAssemblyNameSoftSearch(assemblyName);

            //TODO: Log this...but don't throw an exception
            //            if (project == null)
//                throw new AgileCommonException("Project file not found for assembly name: " + assemblyName);
            return project;
        }


        /// <summary>
        /// Instantiate a new assembly reference with the assembly name
        /// and the base directory to search through.
        /// </summary>
        /// <remarks>Use this when the project has a reference the actual project.
        /// Must be a reference that there is a project file for as an exception gets
        /// thrown if the project file is not found.</remarks>
        /// <returns></returns>
        public static VisualStudioProjectFile InstantiateFromProjectReference(Guid projectGuid
                                                                              , DirectoryInfo rootDirectory)
        {
            // Load the project files that are in the given directory.
            VisualStudioProjectFileCache.GetInstance().LoadedProjectFiles.LoadProjectFilesIn(rootDirectory);

            // Try to find the project file searching for a project by its Guid.
            VisualStudioProjectFile project =
                VisualStudioProjectFileCache.GetInstance().LoadedProjectFiles.GetByProjectGuid(projectGuid);
//            if (project == null)
//                throw new AgileCommonException("Project file not found for ProjectGuid: " + projectGuid);
            return project;
        }
    }
}